package com.tamakloe.guestbook;

import java.text.MessageFormat;
import java.util.ResourceBundle;

import javax.faces.application.FacesMessage;
import javax.faces.application.FacesMessage.Severity;
import javax.faces.component.UIComponent;
import javax.faces.component.UIForm;
import javax.faces.context.FacesContext;

/**
 * This bean is to be associated with a single form in the JSF page. It provides under each a 'form'
 * property which must be bound with the h:form component in the JSF page using the 'binding'
 * attribute. It also provides several methods for success, error and exception message handling.
 */
public abstract class AbstractForm {

    // Constants ----------------------------------------------------------------------------------

    /**
     * The message ID of the message-bundle to be associated with the 'exist' message.
     * It contains one MessageFormat place-holder for the field label.
     */
    public static final String EXIST_MESSAGE_ID = "guestbook.AbstractForm.EXIST";

    /**
     * The message ID of the message-bundle to be associated with the 'invalid' message.
     * It contains one MessageFormat place-holder for the field label.
     */
    public static final String INVALID_MESSAGE_ID = "guestbook.AbstractForm.INVALID";

    /**
     * The message ID of the message-bundle to be associated with the 'unequal' message.
     * It contains two MessageFormat place holders for the label of the both fields.
     */
    public static final String INEQUAL_MESSAGE_ID = "guestbook.AbstractForm.INEQUAL";

    // Statics ------------------------------------------------------------------------------------

    private static ResourceBundle messageBundle = ResourceBundle.getBundle(
        FacesContext.getCurrentInstance().getApplication().getMessageBundle());

    // Properties ---------------------------------------------------------------------------------

    private UIForm form;
    private boolean success;

    // Getters ------------------------------------------------------------------------------------

    /**
     * Returns the form.
     * @return The form.
     */
    public UIForm getForm() {
        return form;
    }

    /**
     * Returns true if the form submit was successful.
     * @return True if the form submit was successful.
     */
    public boolean isSuccess() {
        return success;
    }
    public boolean getSuccess() {
        return success;
    }
    // Setters ------------------------------------------------------------------------------------

    /**
     * Set the form.
     * @param form The form.
     */
    public void setForm(UIForm form) {
        this.form = form;
    }

    /**
     * Set whether the form submit was successful.
     * @param succes Whether the form submit was successful.
     */
    public void setSuccess(boolean success) {
        this.success = success;
    }

    // Special getters ----------------------------------------------------------------------------

    /**
     * Returns the message from the message-bundle associated with the given message ID, formatted
     * with the given parameters, if any.
     * @param messageId The message ID to associate the message from the message-bundle with.
     * @param params The parameters to format the message with using MessageFormat, if necessary.
     * @return The message from the message-bundle associated with the given message ID, formatted
     * with the given parameters, if any.
     */
    public String getMessage(String messageId, Object... params) {
        return MessageFormat.format(messageBundle.getString(messageId), params);
    }

    // Special setters ----------------------------------------------------------------------------

    /**
     * Set the given success message on the current form.
     * @param message The success message to be set on the current form.
     */
    public void setSuccesMessage(String message) {
        setSuccess(true);
        addMessage(form, message, FacesMessage.SEVERITY_INFO);
    }

    /**
     * Set the given error message on the current form.
     * @param message The error message to be set on the current form.
     */
    public void setErrorMessage(String message) {
        addMessage(form, message, FacesMessage.SEVERITY_ERROR);
    }

    /**
     * Set the given exception as error message on the current form. Its trace will also be printed.
     * @param exception The exception to be set as error message on the current form.
     */
    public void setErrorMessage(Exception exception) {
        String message = getMessage(exception.getClass().getName(), exception.getMessage());
        addMessage(form, message, FacesMessage.SEVERITY_ERROR);
        exception.printStackTrace(); // Or use logger.
    }

    /**
     * Set the given error message on the given component.
     * @param component The component to set the given error message on.
     * @param message The error message to be set on the given component.
     */
    public void setErrorMessage(UIComponent component, String message) {
        addMessage(component, message, FacesMessage.SEVERITY_ERROR);
    }

    // Utility (can be re-factored to public utility class) ----------------------------------------

    /**
     * Add the given message with the given severity to the given component.
     * @param component The component to add the given message to.
     * @param message The message to be added to the given component.
     * @param severity The severity to be associated with the given message.
     */
    public static void addMessage(UIComponent component, String message, Severity severity) {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        facesContext.addMessage(component.getClientId(facesContext),
            new FacesMessage(severity, message, null));
    }

    /**
     * Returns the label attribute of the given component.
     * @param component The component to return the label attribute for.
     * @return The label attribute of the given component.
     */
    public static String getLabel(UIComponent component) {
        return (String) component.getAttributes().get("title");
    }

}
